// License Notification
//======================================================
// Copyright (c) 2010 Channel Intelligence Inc.
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// which accompanies this distribution, and is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// ======================================================




using System;
using System.IO;

namespace CIP4.Common
{
    public class CommandFileType
    {
        public bool WritingCommand { get; set; }

        private readonly FileSystemWatcher _watchCommand;

        public string CommandFilePath { get; set; }

        public string Role { get; set; }

        public string CollectionName { get; set; }

        private string _lastMessage;

        public CommandFileType(string aRole, string aPath, string collectionName, FileSystemEventHandler fseh)
        {
            Role = aRole; 

            CommandFilePath = aPath;

            CollectionName = collectionName;

            WriteCommand("started");

            _watchCommand = 
                new FileSystemWatcher
                {
                    Path = GetCommandFilesLocation(),
                    Filter = "*.command.txt",
                    NotifyFilter = NotifyFilters.LastWrite
                };

            _watchCommand.Changed += fseh;

        }

        public void Start()
        {
            _watchCommand.EnableRaisingEvents = true;
        }

        public string GetCommandFileName()
        {
            if (!Directory.Exists(GetCommandFilesLocation()))
                Directory.CreateDirectory(GetCommandFilesLocation());
            return Path.Combine(GetCommandFilesLocation(), CollectionName + "." + Environment.TickCount + ".command.txt");
        }

        public static string GetCommandFilesLocation()
        {
            if (!Directory.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CIP4")))
                Directory.CreateDirectory(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CIP4"));
            return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CIP4");
        }

        public void WriteCommand(string commandText)
        {
            if (WritingCommand)
                return;
            StreamReader rdr = null;
            StreamWriter wrtr = null;
            int retryCount = 0;
            while (retryCount < 5)
            {
                try
                {
                    WritingCommand = true;
                    string text = string.Empty;
                    if (File.Exists(CommandFilePath))
                    {
                        rdr = new StreamReader(CommandFilePath);
                        text = rdr.ReadToEnd();
                        rdr.Close();
                        rdr = null;
                    }
                    text += string.Format(Environment.NewLine + "{0}-{1}-{2}-{3}", Role, CollectionName, DateTime.Now.ToString("MM/dd HH:mm:ss.ffff"), commandText);
                    wrtr = new StreamWriter(CommandFilePath);
                    wrtr.Write(text);
                    wrtr.Close();
                    wrtr = null;
                    return;
                }
                catch (Exception ex)
                {
                    Console.WriteLine("In WriteCommand: " + ex.Message);
                    retryCount += 1;
                    System.Threading.Thread.Sleep(10);
                }
                finally
                {
                    WritingCommand = false;
                    if (rdr != null)
                        rdr.Close();
                    if (wrtr != null)
                        wrtr.Close();
                }
            }
        }

        public string ReadCommand()
        {
            if (WritingCommand)
                return string.Empty;
            StreamReader rdr = null;
            StreamWriter wrtr = null;
            int retryCount = 0;
            while (retryCount < 5)
            {
                try
                {
                    WritingCommand = true;
                    rdr = new StreamReader(CommandFilePath);
                    string text = rdr.ReadToEnd();
                    rdr.Close();
                    rdr = null;
                    string command = text.Substring(text.LastIndexOf(Environment.NewLine)).TrimStart(new[] { '\r', '\n' });
                    string[] parts = command.Split(new[] { '-' });
                    string result;
                    if (parts.Length < 2)
                    {
                        return string.Empty;
                    }
                    else
                    {
                        if (parts[0].StartsWith(Role))
                            return string.Empty;
                        if (command == _lastMessage)
                            return string.Empty;
                        _lastMessage = command;
                        result = parts[parts.Length - 1];
                        if (result != "status")
                        {
                            text += string.Format(Environment.NewLine + "{0}-{1}-{2}-ACK {3}", Role, CollectionName, DateTime.Now.ToString("MM/dd HH:mm:ss.ffff"), result);
                            wrtr = new StreamWriter(CommandFilePath);
                            wrtr.Write(text);
                            wrtr.Close();
                            wrtr = null;
                        }
                    }
                    return result;
                }
                catch (Exception ex)
                {
                    Console.WriteLine("In ReadCommand: " + ex.Message);
                    retryCount += 1;
                    System.Threading.Thread.Sleep(10);
                }
                finally
                {
                    WritingCommand = false;
                    if (rdr != null)
                        rdr.Close();
                    if (wrtr != null)
                        wrtr.Close();
                }
            }
            return string.Empty;
        }

        public string ReadLast()
        {
            StreamReader rdr = null;
            int retryCount = 0;
            while (retryCount < 5)
            {
                try
                {
                    rdr = new StreamReader(CommandFilePath);
                    string text = rdr.ReadToEnd();
                    rdr.Close();
                    rdr = null;
                    string command = text.Substring(text.LastIndexOf(Environment.NewLine)).TrimStart(new[] { '\r', '\n' });
                    string[] parts = command.Split(new[] { '-' });
                    if (parts.Length < 2)
                        return string.Empty;
                    if (command == _lastMessage)
                        return string.Empty;
                    _lastMessage = command;
                    if (command.StartsWith(Role))
                        return string.Empty;
                    
                    return command;
                }
                catch (Exception)
                {
                    retryCount += 1;
                    System.Threading.Thread.Sleep(10);
                }
                finally
                {
                    if (rdr != null)
                        rdr.Close();
                }
            }
            Console.WriteLine("In ReadLast: Retry count exceeded");
            return string.Empty;
        }

        public void Clear()
        {
            int retryCount = 0;
            while (retryCount < 5)
            {
                try
                {
                    File.Delete(CommandFilePath);
                }
                catch (IOException ex)
                {
                    if (!ex.Message.StartsWith("The process cannot access the file"))
                        Console.WriteLine(string.Format("In Clear for {0}: {1}", Role, ex));
                    retryCount += 1;
                    System.Threading.Thread.Sleep(10);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(string.Format("In Clear for {0}: {1}", Role, ex));
                    retryCount += 1;
                    System.Threading.Thread.Sleep(10);
                }
                finally
                {
                    WritingCommand = false;
                }
            }
        }
    }
}
